package datatypes.kdTree;

import java.io.Serializable;
import java.util.Comparator;
import datatypes.Vertex;

/**
 * Compares Vertices.
 * 
 * The comparison starts with the axis this comparator is set to.
 * If the values at the given axis are equal, the values of the next
 * axis are compared, until either differing values have been found, or
 * the axes have been exhausted without finding differences and thus both
 * Vertices found to be equal.
 * 
 * @author nils
 *
 */
public class KdVertexComparator implements Comparator<Vertex>, Serializable {
	private static final long serialVersionUID = 1L;
	
	private int dimension = 2;	/** dimension should match the dimension of the Vertices to be compared. */
	private int axis = 0;		/** The axis to start the comparison on. Can be set using @see {@link #setAxis(int)}.
	
	/**
	 * Creates a new PdVectorComparator for 2-dimensional Vertices.
	 * Axis to be compared can be set as such:
	 * x: set axis to 0
	 * y: set axis to 1
	 * Any other value will cause the comparator to fall back to the x-axis by default.
	 * @param axis 0<=axis<2
	 */
	public KdVertexComparator(int axis) {
		this(axis, 2);
	}
	
	/**
	 * Axis of a 3d vector to be compared can be set as such (vectors of other dimensions analog):
	 * x: set axis to 0
	 * y: set axis to 1
	 * z: set axis to 2
	 * Any other value will cause the comparator to fall back to the x-axis by default.
	 * @param axis 0<=axis<3
	 * @param dimension
	 */
	KdVertexComparator(int axis, int dimension) {
		this.dimension = dimension;
		if (axis < dimension && axis >= 0) {
			this.axis = axis;
		}
	}
	
	/**
	 * Axis of a 3d vector to be compared can be set as such (vectors of other dimensions analog):
	 * x: set axis to 0
	 * y: set axis to 1
	 * z: set axis to 2
	 * Any other value will cause the comparator to fall back to the x-axis by default.
	 * @param axis 0<=axis<3
	 */
	public void setAxis(int axis) {
		if (axis < dimension && axis >= 0) {
			this.axis = axis;
		}
	}

	/**
	 * Compares two Vertices starting at the axis set for this comparator.
	 * @see #setAxis(int)
	 * 
	 * Starting at the given axis, the result of the comparison between the 
	 * two entries at the given axis are returned if these entries are not
	 * equal. If they are equal, the values of the next axis are compared
	 * until either a pair has been found that is not equal or all pairs of
	 * values have been found to be equal.
	 * @see "DeBerg: Computational Geometry on pages 110f".
	 * 
	 * @param v0
	 * @param v1
	 * @return The return value is the result of the first pair of values that are
	 * not equal or 0 if all pairs are equal.
	 */
	public int compare(Vertex v0, Vertex v1) {
		Double value0 = null;
		Double value1 = null;
		int comparison = 0;
		int axis = this.axis;	// local copy since it may get altered
		for (int i = 0; i < dimension; i++) {
			value0 = v0.getEntry(axis);
			value1 = v1.getEntry(axis);
			comparison = value0.compareTo(value1);
			if (comparison != 0) {
				break;
			}
			// select next axis if values were found to be equal
			axis++;
			axis %= dimension;
		}
		return comparison;
	}

}
